(require '[fx-clj.internal.util])
(fx-clj.internal.util/ns-start-loading 'fx-clj.sandbox)

(ns ^:no-doc fx-clj.sandbox
  (:import (javafx.scene.input KeyCode))
  (:require
    [fx-clj.elements :as fx]
    [fx-clj.core.run :refer [run<!!]]
    [fx-clj.core.pset :refer [pset!]]))

;; <<----------------------
(fx-clj.internal.util/ns-libs-loaded 'fx-clj.sandbox)
;; ---------------------->>

(def ^:private auto-inc (atom 0))

(defn- extract-view [refresh-fn]
  (let [v (refresh-fn)]
    (cond
      (map? v) v
      :else {:root v})))

(defn sandbox
  "Creates a JavaFX stage with the root element of the stage's scene set to
  the result of evaluating refresh-fn. If F5 is pressed within the stage,
  refresh-fn will be re-evaluated and its new result will be bound to as the
  root of the scene. This can be very useful for prototyping.

  Suggested usage:

  (defn my-refresh-fn [] (do-create-view....))
  (sandbox #'my-refresh-fn)
  ;; By binding to a var,  my-refresh-fn can be  easily updated and reloaded
  ;; at the REPL"
  [refresh-fn & {:keys [title maximized width height]
                 :or   {title (str "Sandbox" (swap! auto-inc inc))}}]
  (run<!!
    (let [{:keys [root on-close
                  on-showing on-shown
                  on-hiding on-hidden]} (extract-view refresh-fn)
          scene (fx/scene root)
          stage (fx/stage)]
      (pset! scene
             {:on-key-pressed
              (fn do-sandbox-refresh [e]
                (when (= KeyCode/F5 (.getCode e))
                  (let [{:keys [root]} (extract-view refresh-fn)]
                    (pset! scene {:root root}))))})
      (.setScene stage scene)
      ;(.initModality stage Modality/NONE)
      (pset! stage {:title            title
                    :on-close-request on-close
                    :on-showing       on-showing
                    :on-shown         on-shown
                    :on-hiding        on-hiding
                    :on-hidden        on-hidden
                    :modality         :none})
      (when maximized (.setMaximized stage true))
      (when width (.setWidth stage width))
      (when height (.setHeight stage height))
      (.show stage)
      stage)))


(fx-clj.internal.util/ns-loaded 'fx-clj.sandbox)